[GitHub Actions] 三項演算子ライクな記述でブランチ名に応じて必要なシークレットのみ取得する
こんにちは、CX事業本部 IoT事業部の若槻です。
GitHub Actionsで、不必要なシークレットまで取得するWorkflowを組んでしまっていませんか?私は今まで組んでしまっていました。
そこで今回は、GitHub Actionsで三項演算子(condition ? exprIfTrue : exprIfFalse
)ライクな記述を使用して、ブランチ名に応じて必要なシークレットのみ取得するWorkflowを作ってみました。
不必要なシークレットまで取得してしまうパターン
AWSの開発/ステージング/本番環境の認証情報を使用してシステムのデプロイを行うWorkflowを想定します。開発はdevelop
、ステージングはstaging
、本番はmain
のブランチにマージが行われた時にそれぞれの環境にデプロイが行われる想定です。
on: push: paths-ignore: - '**/*.md' jobs: integration: runs-on: ubuntu-latest steps: - run: echo "中略" deploy: runs-on: ubuntu-latest needs: integration if: | github.ref_name == 'develop' || github.ref_name == 'staging' || github.ref_name == 'main' env: DEV_AWS_OIDC_ROLE_ARN: ${{ secrets.DEV_AWS_OIDC_ROLE_ARN }} STG_AWS_OIDC_ROLE_ARN: ${{ secrets.STG_AWS_OIDC_ROLE_ARN }} PRD_AWS_OIDC_ROLE_ARN: ${{ secrets.PRD_AWS_OIDC_ROLE_ARN }} AWS_REGION: us-east-1 permissions: id-token: write contents: read steps: - name: debug run: | echo Branch: ${{ github.ref_name }} echo DEV_AWS_OIDC_ROLE_ARN: ${DEV_AWS_OIDC_ROLE_ARN/::*:/::XXXXXXXXXXXX:} echo STG_AWS_OIDC_ROLE_ARN: ${STG_AWS_OIDC_ROLE_ARN/::*:/::XXXXXXXXXXXX:} echo PRD_AWS_OIDC_ROLE_ARN: ${PRD_AWS_OIDC_ROLE_ARN/::*:/::XXXXXXXXXXXX:} - name: Assume Role DEV if: ${{ github.ref_name == 'develop' }} uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: ${{ env.DEV_AWS_OIDC_ROLE_ARN }} aws-region: ${{env.AWS_REGION}} - name: Assume Role STG if: ${{ github.ref_name == 'staging' }} uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: ${{ env.STG_AWS_OIDC_ROLE_ARN }} aws-region: ${{env.AWS_REGION}} - name: Assume Role PRD if: ${{ github.ref_name == 'main' }} uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: ${{ env.PRD_AWS_OIDC_ROLE_ARN }} aws-region: ${{env.AWS_REGION}} # checkout & some build & deploy
env
では開発/ステージング/本番環境それぞれの認証情報をシークレットからすべて取得して環境変数に格納するようになっています。
env: DEV_AWS_OIDC_ROLE_ARN: ${{ secrets.DEV_AWS_OIDC_ROLE_ARN }} STG_AWS_OIDC_ROLE_ARN: ${{ secrets.STG_AWS_OIDC_ROLE_ARN }} PRD_AWS_OIDC_ROLE_ARN: ${{ secrets.PRD_AWS_OIDC_ROLE_ARN }}
認証情報を使用した認証(AssumeRole)処理では、ブランチに応じてどの環境変数を使用して認証を行うかの条件分岐を書いています。
- name: Assume Role DEV if: ${{ github.ref_name == 'develop' }} uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: ${{ env.DEV_AWS_OIDC_ROLE_ARN }} aws-region: ${{env.AWS_REGION}} - name: Assume Role STG if: ${{ github.ref_name == 'staging' }} uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: ${{ env.STG_AWS_OIDC_ROLE_ARN }} aws-region: ${{env.AWS_REGION}} - name: Assume Role PRD if: ${{ github.ref_name == 'main' }} uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: ${{ env.PRD_AWS_OIDC_ROLE_ARN }} aws-region: ${{env.AWS_REGION}}
そしてこのWorkflowを使用して、例えばfeature/xxxxxxx
ブランチからdevelop
ブランチへマージすると、開発環境に対するAssumeRoleが行われますが、シークレットの取得は全環境に対して行われてしまいます。.../dev-github-oidc-role
が開発、.../stg-github-oidc-role
がステージング、.../prd-github-oidc-role
が本番環境用の認証情報です。
このシークレットをすべて取得する処理は認証情報を不必要に暴露させるため、セキュリティリスクに繋がります。開発環境へのデプロイを行うのに、ステージングおよび本番環境の認証情報をシークレットから取得する必要はないはずです。
必要なシークレットのみ取得してみる
そこで、Workflowを次のように修正します。
on: push: paths-ignore: - '**/*.md' jobs: integration: runs-on: ubuntu-latest steps: - run: echo "中略" deploy: runs-on: ubuntu-latest needs: integration if: | github.ref_name == 'develop' || github.ref_name == 'staging' || github.ref_name == 'main' env: AWS_OIDC_ROLE_ARN: | ${{ github.ref_name == 'main' && secrets.PRD_AWS_OIDC_ROLE_ARN || github.ref_name == 'staging' && secrets.STG_AWS_OIDC_ROLE_ARN || secrets.DEV_AWS_OIDC_ROLE_ARN }} AWS_REGION: us-east-1 permissions: id-token: write contents: read steps: - name: debug run: | echo Branch: ${{ github.ref_name }} echo AWS_OIDC_ROLE_ARN: ${AWS_OIDC_ROLE_ARN/::*:/::XXXXXXXXXXXX:} - name: Assume Role uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: ${{ env.AWS_OIDC_ROLE_ARN }} aws-region: ${{env.AWS_REGION}} # checkout & some build & deploy
GitHub ActionsのExpressionsでは、次のような三項演算子ライクな記述が可能です。それを使用して単一の環境変数に対して現在のブランチ名に応じたシークレットの指定が可能です。
env: AWS_OIDC_ROLE_ARN: | ${{ github.ref_name == 'main' && secrets.PRD_AWS_OIDC_ROLE_ARN || github.ref_name == 'staging' && secrets.STG_AWS_OIDC_ROLE_ARN || secrets.DEV_AWS_OIDC_ROLE_ARN }}
認証情報を使用した認証(AssumeRole)処理で、指定する環境変数はブランチによって変わらないため、一つの処理を済めば事足ります。
- name: Assume Role uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: ${{ env.AWS_OIDC_ROLE_ARN }} aws-region: ${{env.AWS_REGION}}
feature/xxxxxxx
からdevelop
へマージすると、開発環境用の認証情報がAWS_OIDC_ROLE_ARN
に格納され、それを使用してAssumeRoleが行われました!
develop
からstaging
へマージすると、ステージング環境用の認証情報がAWS_OIDC_ROLE_ARN
に格納され、それを使用してAssumeRoleが行われました!
staging
からmain
へマージすると、本番環境用の認証情報がAWS_OIDC_ROLE_ARN
に格納され、それを使用してAssumeRoleが行われました!
おわりに
GitHub Actionsで三項演算子ライクな記述を使用して、ブランチ名に応じて必要なシークレットのみ取得するWorkflowを作ってみました。
GitHub ActionsのExpressionsは使いこなすと様々な表現が出来ることが分かり、いじっていて楽しかったです。こういう小さな積み重ねを大事にしたいですね。
参考
- Possible to use conditional in the "env" section of a job? - Code to Cloud / GitHub Actions - GitHub Community
- How to write multi-line condition in if - Code to Cloud / GitHub Actions - GitHub Community
- Push時はCIのみ、Merge時はCIおよびCDを実行するGitHub Actionsを作る(単一のWorkflowで) | DevelopersIO
以上